package com.health.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.health.common.PageBean;
import com.health.common.QueryParam;
import com.health.common.WXConstants;
import com.health.dto.OrderDto;
import com.health.mapper.OrderMapper;
import com.health.pojo.Order;
import com.health.pojo.OrderSet;
import com.health.pojo.Setmeal;
import com.health.service.OrderService;
import com.health.service.OrderSetService;
import com.health.service.SetmealService;
import com.health.utils.WXPayUtil;
import com.health.vo.OrderInfoVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
@RequiredArgsConstructor
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final OrderSetService orderSetService;
    private final SetmealService setmealService;

    /**
     * 提交预约
     *
     * @param dto
     * @return
     */
    @Override
    public Integer submitOrder(OrderDto dto) {
        //1. 先判断当前预约日期是否可用
        OrderSet orderSet = orderSetService.query().eq("order_date", dto.getOrderDate()).one();
        if (orderSet == null) {
            // 当前日期不可预约
            throw new RuntimeException("当前日期不可预约");
        }

        if (orderSet.getReservations() >= orderSet.getNumber()) {
            // 当前日期已满
            throw new RuntimeException("当前日期预约已满");
        }


        //2. 向预约表中添加数据     将dto数据 封装到 pojo 中
        Order order = new Order();
        BeanUtils.copyProperties(dto, order); //将左边对象中的数据 拷贝 到右边对象中    根据属性名称来识别
        //补全信息
        order.setMemberId(1); //    会员id
        order.setStatus(1); //    预约状态
        order.setType(1); //   预约类型

        //添加数据到数据库
        this.save(order);


        //3. 修改预约设置信息，将对应的已预约数量+1
        orderSetService.update().eq("order_date", dto.getOrderDate()).set("reservations", orderSet.getReservations() + 1).update();

        //4. 返回预约对象id
        return order.getId();
    }

    /**
     * 获取预约记录
     *
     * @param id
     * @return
     */
    @Override
    public OrderInfoVO getOrderInfo(Integer id) {
        Order order = this.getById(id);
        //查询套餐名称
        Setmeal setmeal = setmealService.getById(order.getSetmealId());

        // 创建预约信息对象 封装数据
        OrderInfoVO orderInfoVO = new OrderInfoVO();
        orderInfoVO.setSetmealName(setmeal.getName()); //设置 套餐名称
        orderInfoVO.setMemberName(order.getName()); //设置 预约人
        orderInfoVO.setSex(order.getSex()); //性别
        orderInfoVO.setOrderDate(order.getOrderDate()); // 设置 预约日期
        orderInfoVO.setType(order.getType()); // 设置 预约类型
        /*BeanUtils.copyProperties(order, orderInfoVO);*/

        return orderInfoVO;
    }

    /**
     * 分页查询预约记录
     *
     * @param param
     * @return
     */
    @Override
    public PageBean pageQuery(QueryParam param) {
        Page<Order> page = new Page<>(param.getCurrentPage(), param.getPageSize());
        this.query().like(param.getQueryString() != null, "name", param.getQueryString()).or().like(param.getQueryString() != null, "telephone", param.getQueryString()).page(page);
        return new PageBean(page.getRecords(), page.getTotal());
    }

    /**
     * 获取支付二维码
     *
     * @param id
     * @return
     */
    @Override
    public String orderPay(Long id) {

        Order order = this.getById(id);
        Setmeal setmeal = setmealService.getById(order.getSetmealId());

        //以map集合的形式，封装微信支付的请求参数
        Map<String, String> map = Maps.newHashMap();
        map.put("appid", WXConstants.APP_ID); //公众账号ID
        map.put("mch_id", WXConstants.MCH_ID);//商户号
        map.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
        map.put("body", setmeal.getName());//商品描述
        map.put("out_trade_no", "T" + DateUtil.currentSeconds() + id);//商户订单号
        map.put("total_fee", "1");//标价金额
        map.put("spbill_create_ip", "127.0.0.1");//终端IP
        map.put("notify_url", WXConstants.NOTIFY_URL);//通知地址
        map.put("trade_type", "NATIVE");//Native支付

        //将map集合转成xml格式，并且生成参数的签名
        try {
            String xml = WXPayUtil.generateSignedXml(map);
            //和微信支付对接，获取支付二维码地址
            HttpResponse response = HttpUtil.createPost(WXConstants.API_URL) //POST请求
                    .body(xml) //请求体的数据
                    .header("Content-Type", "application/xml")//请求体：表述的是请求体的数据格式为xml类型
                    .execute();//发送请求
            String xmlBody = response.body(); //xml
            //将xml格式转为map集合
            map = WXPayUtil.xmlToMap(xmlBody);
            log.info("微信支付返回数据 {}", map);
        } catch (Exception e) {
            throw new RuntimeException("调用微信支付接口失败");
        }

        //判断微信返回的数据是否是SUCCESS
        String returnCode = map.get("return_code");
        String resultCode = map.get("result_code");
        String errCodeDes = map.get("err_code_des");

        if (StrUtil.equalsAnyIgnoreCase("FAIL", returnCode, resultCode)) {
            //有异常
            log.error("微信支付结果异常 {}", errCodeDes);
            throw new RuntimeException(errCodeDes);
        }

        String codeUrl = map.get("code_url");
        log.info("微信支付二维码地址 {}", codeUrl);
        return codeUrl;
    }
}
